 1.车辆监控之Structured Streaming中Structured Streaming发展历史
   
   1).Spark Streaming
   在2.0 之前，Spark Streaming作为核心API的扩展，针对实时数据流，提供了一套可扩展、高吞吐、
可容错的流式计算模型。Spark Streaming会接收实时数据源的数据，并切分成很多小的batches，然
后被Spark Engine执行，产出同样由很多小的batchs组成的结果流。本质上，这是一种micro-batch
(微批处理)的方式处理，用批的思想去处理流数据.这种设计让Spark Streaming面对复杂的流式处理
场景时捉襟见肘。
   其实在流计算发展的初期，市面上主流的计算引擎本质上都只能处理特定的场景，
   spark streaming这种构建在微批处理上的流计算引擎，比较突出的问题就是处理延时较高（无法优化
到秒以下的数量级），以及无法支持基于event_time的时间窗口做聚合逻辑。
   在这段时间，流式计算一直没有一套标准化、能应对各种场景的模型，直到2015年google发表了The
   Dataflow Model的论文。
   https://yq.aliyun.com/articles/73255
   2).Dataflow模型
   在日常商业运营中，无边界、乱序、大规模数据集越来越普遍（例如，网站日志，手机应用统计，传
感器网络）。同时，对这些数据的消费需求也越来越复杂，比如说按事件发生时间序列处理数据，按数
据本身的特征进行窗口计算等等。同时人们也越来越苛求立刻得到数据分析结果。
   作为数据工作者，不能把无边界数据集（数据流）切分成有边界的数据，等待一个批次完整后处理。
   
   相反地，应该假设永远无法知道数据流是否终结，何时数据会变完整。唯一确信的是，新的数据会源源
不断而来，老的数据可能会被撤销或更新。
   由此，google工程师们提出了Dataflow模型，从根本上对从前的数据处理方法进行改进。
   (1).核心思想
   对无边界，无序的数据源，允许按数据本身的特征进行窗口计算，得到基于事件发生时间的有序结果，
并能在准确性、延迟程度和处理成本之间调整。
   (2).四个维度
   抽象出四个相关的维度，通过灵活地组合来构建数据处理管道，以应对数据处理过程中的各种复杂的场
景 
   what 需要计算什么
   where 需要基于什么时间（事件发生时间）窗口做计算
   when 在什么时间（系统处理时间）真正地触发计算
   how 如何修正之前的计算结果
   论文的大部分内容都是在说明如何通过这四个维度来应对各种数据处理场景。
   (3).相关概念
   在现实场景中，从一个事件产生，到它被数据分析系统收集到，要经过非常复杂的链路，这本身就会
存在一定的延时，还会因为一些特殊的情况加剧这种情况。比如基于移动端APP的用户行为数据，会因
为手机信号较差、没有wifi等情况导致无法及时发送到服务端系统。面对这种时间上的偏移，数据处理
模型如果只考虑处理时间，势必会降低最终结果的正确性。
   事件时间和处理时间
   event_time，事件的实际发生时间
   process_time，处理时间，是指一个事件被数据处理系统观察/接收到的时间
   
   现在假设，你正在去往地下停车场的路上，并且打算用手机点一份外卖。选好了外卖后，你就用在线支
付功能付款了，这个时候是12点05分。恰好这时，你走进了地下停车库，而这里并没有手机信号。因此
外卖的在线支付并没有立刻成功，而支付系统一直在Retry重试“支付”这个操作。
   当你找到自己的车并且开出地下停车场的时候，已经是12点15分了。这个时候手机重新有了信号，手机
上的支付数据成功发到了外卖在线支付系统，支付完成。
   在上面这个场景中你可以看到，支付数据的事件时间是12点05分，而支付数据的处理时间是12点15分
   
   窗口
   除了一些无状态的计算逻辑（如过滤，映射等），经常需要把无边界的数据集切分成有限的数据片以便
于后续聚合处理（比如统计最近5分钟的XX等），窗口就应用于这类逻辑中，常见的窗口包括：
   sliding window，滑动窗口，除了窗口大小，还需要一个滑动周期，比如小时窗口，每5分钟滑动一
次。
   ixed window，固定窗口，按固定的窗口大小定义，比如每小时、天的统计逻辑。
   固定窗口可以看做是滑动窗口的特例，即窗口大小和滑动周期相等。
   
   sessions，会话窗口，以某一事件作为窗口起始，通常以时间定义窗口大小（也有可能是事件次数），
发生在超时时间以内的事件都属于同一会话，比如统计用户启动APP之后一段时间的浏览信息等。
   总结
   论文中远不止这些内容，还有很多编程模型的说明和举例，感兴趣的同学可以自行阅读。
   https://yq.aliyun.com/articles/73255
   
   除了论文，google还开源了Apache Beam项目，基本上就是对Dataflow模型的实现，目前已经成为
Apache的顶级项目，但是在国内使用不多。国内使用的更多的是后面要学习的Flink，因为阿里大力推
广Flink，甚至把花7亿元把Flink收购了.

 2.Structured Streaming
   
   1).介绍
   官网地址
   http://spark.apache.org/docs/latest/structured-streaming-programming-guide.html
   
   也许是对Dataflow模型的借鉴，也许是英雄所见略同，spark在2.0 版本中发布了新的流计算的API，
Structured Streaming/结构化流。
       Structured Streaming是一个基于Spark SQL引擎的可扩展、容错的流处理引擎。统一了流、批的
编程模型，你可以使用静态数据批处理一样的方式来编写流式计算操作。并且支持基于event_time的时间
窗口的处理逻辑。
       Structured Streaming会以一种增量的方式来执行这些操作，并且持续更新结算结果。
	        可以使用Scala、Java、Python或R中的DataSet／DataFrame API来表示流聚合、事件时间
窗口、流到批连接等。此外，
            Structured Streaming会通过checkpoint和预写日志等机制来实现Exactly-Once语义。
   简单来说，对于开发人员来说，根本不用去考虑是流式计算，还是批处理，只要使用同样的方式来编写
计算操作即可，Structured Streaming提供了快速、可扩展、容错、端到端的一次性流处理，而用户无需
考虑更多细节
   
   默认情况下，结构化流式查询使用微批处理引擎进行处理，该引擎将数据流作为一系列小批处理作业进
行处理，从而实现端到端的延迟，最短可达100毫秒，并且完全可以保证一次容错。自Spark 2.3 以来，引
入了一种新的低延迟处理模式,称为连续处理,它可以在至少一次保证的情况下实现低至1毫秒的端到端延迟。
也就是类似于Flink那样的实时流,而不是小批量处理。实际开发可以根据应用程序要求选择处理模式。
   2).API
   (1).Spark Streaming 时代 -DStream-RDD
   Spark Streaming 采用的数据抽象是DStream，而本质上就是时间上连续的RDD，对数据流的操作就是
针对RDD的操作
   (2).Structured Streaming 时代 - DataSet/DataFrame -RDD
   Structured Streaming是Spark2.0 新增的可扩展和高容错性的实时计算框架，它构建于Spark SQL引
擎，把流式计算也统一到DataFrame/Dataset里去了。
   Structured Streaming 相比于 Spark Streaming 的进步就类似于 Dataset 相比于 RDD 的进步
   3).编程模型
   编程模型概述
   一个流的数据源从逻辑上来说就是一个不断增长的动态表格，随着时间的推移，新数据被持续不断地添
加到表格的末尾。
       用户可以使用 Dataset/DataFrame 函数式API或者 SQL 来对这个动态数据源进行实时查询。每次
查询在逻辑上就是对当前的表格内容执行一次 SQL 查询。
       什么时候执行查询则是由用户通过触发器（Trigger）来设定时间(毫秒级)。用户既可以设定执行周
期让查询尽可能快地执行，从而达到实时的效果也可以使用默认的触发。
   一个流的输出有多种模式，
       可以是基于整个输入执行查询后的完整结果，complete
       也可以选择只输出与上次查询相比的差异，update
       或者就是简单地追加最新的结果。append
   这个模型对于熟悉 SQL 的用户来说很容易掌握，对流的查询跟查询一个表格几乎完全一样，十分简
洁，易于理解
   核心思想
   Structured Streaming最核心的思想就是将实时到达的数据看作是一个不断追加的unbound table无界
表，到达流的每个数据项(RDD)就像是表中的一个新行被附加到无边界的表中.这样用户就可以用静态结构
化数据的批处理查询方式进行流计算，如可以使用SQL对到来的每一行数据进行实时查询处理；
   
   应用场景
   Structured Streaming将数据源映射为类似于关系数据库中的表，然后将经过计算得到的结果映射为另
一张表，完全以结构化的方式去操作流式数据，这种编程模型非常有利于处理分析结构化的实时数据；
   
   WordCount图解
   如图所示，
第一行表示从socket不断接收数据，
第二行是时间轴，表示每隔1秒进行一次数据处理，
第三行可以看成是之前提到的“unbound table"，
第四行为最终的wordCounts是结果集。
当有新的数据到达时，Spark会执行“增量"查询，并更新结果集；
该示例设置为Complete Mode，因此每次都将所有数据输出到控制台；
    
	(1).在第1秒时，此时到达的数据为"cat dog"和"dog dog"，因此我们可以得到第1秒时的结果集cat=1
dog=3,并输出到控制台；
	(2).当第2秒时，到达的数据为"owl cat"，此时"unbound table"增加了一行数据"owl cat"，执行word
count查询并更新结果集，可得第2秒时的结果集为cat=2 dog=3 owl=1,并输出到控制台；
	(3).当第3秒时，到达的数据为"dog"和"owl"，此时"unbound table"增加两行数据"dog"和"owl"，执行
word count查询并更新结果集，可得第3秒时的结果集为cat=2 dog=4 owl=2；
   